﻿using System;
using System.ComponentModel;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Windows;
using Caliburn.Micro;
using PurchaseSales.Manage.Common.AOP;
using PurchaseSales.Manage.Common.Extensions;
using PurchaseSales.Manage.Model.Entities;
using PurchaseSales.Manage.Services;
using PurchaseSales.Manage.Views.UserControls;
using ReactiveUI;
using ReactiveUI.Xaml;

namespace PurchaseSales.Manage.ViewModels
{
    public class CustomerViewModel : Screen
    {
        private readonly ICustomerRepository _repository;
        private readonly IWindowManager _windowManager;

        public ReactiveAsyncCommand SelectedCustomerCommand { get; set; }
        public ReactiveAsyncCommand AddCommand { get; set; }
        public ReactiveAsyncCommand RemoveCommand { get; set; }
        public ReactiveAsyncCommand EditCommand { get; set; }
        public ReactiveAsyncCommand LoadCommand { get; set; }

        private ObservableAsPropertyHelper<ReactiveCollection<Customer>> _customers;
        private ObservableAsPropertyHelper<Customer> _selectedCustomers;

        public CustomerViewModel(ICustomerRepository repository, IWindowManager windowManager)
        {
            _repository = repository;
            _windowManager = windowManager;

            LoadCommand = new ReactiveAsyncCommand();
            var observable = LoadCommand.RegisterAsyncFunction(_ =>
                {
                    var customers = _repository.GetAll();
                    return customers.ToObservable().CreateCollection();
                });
            _customers = new ObservableAsPropertyHelper<ReactiveCollection<Customer>>(observable, _ =>
                             {
                                 NotifyOfPropertyChange(() => Customers);
                             });
            SelectedCustomerCommand = new ReactiveAsyncCommand();
            var @select = SelectedCustomerCommand.Select(o =>
                                                             {
                                                                 var customer = o as Customer;
                                                                 return customer;
                                                             });
            _selectedCustomers = new ObservableAsPropertyHelper<Customer>(@select, _ => { });
            AddCommand = new ReactiveAsyncCommand();
            AddCommand.Subscribe(o =>
                                     {
                                         var customer = DataBindingFactory.Create<Customer>();
                                         var dialogViewModel = IoC.Get<IShowDialogViewModel<Customer>>();
                                         dialogViewModel.ShowDialogContent = new AddCustomer();
                                         dialogViewModel.Entity = customer;
                                         CanConfirm = dialogViewModel.CanConfirm;
                                         NotifyEntityChanged(customer);
                                         var showDialog = _windowManager.ShowDialog(dialogViewModel);
                                         if (showDialog == true)
                                         {
                                             Customers.Add(dialogViewModel.Entity);
                                             _repository.Save(dialogViewModel.Entity);
                                         }
                                     });
            RemoveCommand = new ReactiveAsyncCommand(_selectedCustomers.Select(x => x != null).StartWith(false));
            RemoveCommand.Subscribe(o =>
            {
                _repository.MakeTransient(SelectedCustomer);
                Customers.Remove(SelectedCustomer);
                _repository.Commit();
            });
            RemoveCommand.ThrownExceptions.Subscribe(_ => MessageBox.Show("Remove Error"));

            EditCommand = new ReactiveAsyncCommand(_selectedCustomers.Select(x => x != null).StartWith(false));
            EditCommand.Subscribe(o =>
                                                {
                                                    var dialogViewModel = IoC.Get<IShowDialogViewModel<Customer>>();
                                                    dialogViewModel.ShowDialogContent = new AddCustomer();
                                                    dialogViewModel.Entity = SelectedCustomer;
                                                    CanConfirm = dialogViewModel.CanConfirm;
                                                    NotifyEntityChanged(SelectedCustomer);

                                                    var showDialog = _windowManager.ShowDialog(dialogViewModel);
                                                    if (showDialog == true)
                                                    {
                                                        _repository.Save(dialogViewModel.Entity);
                                                    }
                                                    else
                                                    {
                                                        _repository.Evict(dialogViewModel.Entity);
                                                        LoadCommand.Execute(this);
                                                    }
                                                });
        }

        public Customer SelectedCustomer
        {
            get { return _selectedCustomers.Value; }
        }

        public ReactiveCollection<Customer> Customers
        {
            get { return _customers.Value; }
        }
        public Action<bool> CanConfirm;
        public bool CanSave(Customer customer)
        {
            return !string.IsNullOrEmpty(customer.Number) && !string.IsNullOrEmpty(customer.Name);

        }
        private void NotifyEntityChanged(Customer customer)
        {
            var entity = customer as INotifyPropertyChanged;
            entity.SafeInvoke(x => x.PropertyChanged += (sender, args) =>
                                                            {
                                                                CanConfirm.Invoke(CanSave(customer));
                                                            });
        }
    }
}